package internal

import (
	"context"
	"encoding/json"
	"gitee.com/alex_li/weight/internal/etc"
	"gitee.com/alex_li/weight/internal/monitor"
	"gitee.com/alex_li/weight/internal/mq"
	"github.com/lishimeng/go-log"
	"github.com/lishimeng/serial-finder"
	"sync"
	"time"
)

var s sync.RWMutex

var weights map[string]*monitor.Weight

var measurement map[string]monitor.WeightData

var finder sfinder.Finder


func init() {
	weights = make(map[string]*monitor.Weight)
	measurement = make(map[string]monitor.WeightData)
}

func Setup(ctx context.Context) (err error) {

	finder =sfinder.New(sfinder.SerialType(etc.Config.Serial.Vendor))

	listener = func(name string, data monitor.WeightData) {
		s.Lock()
		measurement[name] = data
		s.Unlock()
	}
	err = setupWeightMonitor(ctx)
	if err != nil {
		return
	}
	mq.StartIot()
	upload(ctx)
	return
}

func upload(ctx context.Context) {

	go func() {
		for {
			select {
			case <-ctx.Done():
				break
			default:
				_upload()
				time.Sleep(time.Millisecond*350)
			}
		}
	}()
}

func _upload() {
	if !mq.Usable {
		return
	}
	value := _measurement()
	if value == nil {
		return
	}

	bs, err := json.Marshal(value)
	if err != nil {
		log.Info(err)
	} else {
		log.Info(string(bs))
		mq.Session.Publish(bs)
	}
}

func _measurement() (d *monitor.WeightData) {

	var r monitor.WeightData
	s.Lock()
	if len(measurement) > 0 {
		for _, value := range measurement {
			if value.Data > r.Data {
				r = value
			}
		}
		d = &r
	}
	s.Unlock()
	return
}

func setupWeightMonitor(ctx context.Context) (err error) {

	go func() {
		for {
			select {
			case <-ctx.Done():
				break
			default:
				setupWeight(ctx)
				time.Sleep(time.Second*2)
			}
		}
	}()
	return
}

func setupWeight(ctx context.Context) {

	// 清理不可用的设备-------------------------
	var marker []string
	for name, w := range weights {
		if !w.State {
			marker = append(marker, name)
		}
	}
	for _, name := range marker {
		log.Info("remove weight: %s", name)
		delete(weights, name)
		s.Lock()
		delete(measurement, name)
		s.Unlock()
	}
	// --------------------------------------

	list, err := finder.Find()
	for _, uart := range list {
		var w *monitor.Weight
		if _, ok := weights[uart.Name]; ok { // 已经在设备列表中
			continue
		}

		log.Info("init weight: %s", uart.Name)
		w, err = Weight(ctx, uart.Name, etc.Config.Serial.Baud)
		if err != nil {
			return
		}
		weights[uart.Name] = w
	}
}